package io.xxx.omni.oss.job

import com.google.common.base.CaseFormat
import io.xxx.omni.oss.client.PlatformClient
import io.xxx.omni.oss.client.StoreClient
import io.xxx.omni.oss.core.Synchronizer
import io.xxx.omni.oss.domain.DocumentType
import io.xxx.omni.oss.domain.Job
import io.xxx.omni.oss.domain.Platform
import io.xxx.omni.oss.repository.mapper.JobMapper
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.BeanFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.support.BeanDefinitionBuilder
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
import org.springframework.context.annotation.Configuration
import org.springframework.context.support.GenericApplicationContext
import org.springframework.scheduling.annotation.EnableScheduling
import org.springframework.scheduling.annotation.SchedulingConfigurer
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler
import org.springframework.scheduling.config.ScheduledTaskRegistrar
import java.time.LocalDateTime

@EnableScheduling
@Configuration
class JobInitializer : ApplicationContextAware, SchedulingConfigurer {

    private val log: Logger = LoggerFactory.getLogger(javaClass)

    @Autowired
    private lateinit var jobMapper: JobMapper

    @Autowired
    private lateinit var platformClient: PlatformClient

    @Autowired
    private lateinit var storeClient: StoreClient

    private lateinit var applicationContext: GenericApplicationContext

    private lateinit var beanFactory: BeanFactory

    override fun setApplicationContext(applicationContext: ApplicationContext) {
        this.applicationContext = applicationContext as GenericApplicationContext
        this.beanFactory = applicationContext.beanFactory
    }

    override fun configureTasks(taskRegistrar: ScheduledTaskRegistrar) {
        initScheduler(taskRegistrar)

        val platforms = platformClient.getAll()
        for (platform in platforms) {
            when (platform.id) {
                "aikucun" -> registerTask(taskRegistrar, platform, "akc")
                "dangdang" -> registerTask(taskRegistrar, platform, "dd")
                "jingdong" -> registerTask(taskRegistrar, platform, "jd")
                "kuaishou" -> registerTask(taskRegistrar, platform, "ks")
                "suning" -> registerTask(taskRegistrar, platform, "sn")
                "taobao" -> registerTask(taskRegistrar, platform, "tb")
                "tengxunhuiju" -> registerTask(taskRegistrar, platform, "txhj")
                "weipinhui" -> registerTask(taskRegistrar, platform, "wph")
                "xiaohongshu" -> registerTask(taskRegistrar, platform, "xhs")
                "yunji" -> registerTask(taskRegistrar, platform, "yj")
            }
        }
    }

    private fun registerTask(
        taskRegistrar: ScheduledTaskRegistrar,
        platform: Platform,
        shorthand: String,
        documentTypes: List<DocumentType> = listOf(DocumentType.TRADE, DocumentType.REFUND),
    ) {
        val defaultCron = "*/3 * * * * ?"
        val now = LocalDateTime.now()
        val stores = storeClient.getAll(platform.id)
        for (store in stores) {
            val typeNames = documentTypes.map { it.desc.replaceFirstChar { fc -> fc.titlecase() } }
            typeNames.forEach {
                val prefix = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, shorthand)
                val jobId = "${shorthand}${it}Synchronizer${store.id}"
                val job = Job(
                    jobId,
                    platform.id,
                    store.id,
                    "${platform.name}店铺[${store.id}]${if (it == "Trade") "订单" else "退单"}同步",
                    "io.xxx.omni.oss.custom.${prefix}${it}Synchronizer",
                    false,
                    defaultCron,
                    now,
                    now,
                )

                val jobInDB = jobMapper.selectById(job.id)
                if (jobInDB == null) {
                    jobMapper.insert(job)
                } else {
                    val beanDefinition = BeanDefinitionBuilder
                        .genericBeanDefinition(job.className)
                        .addPropertyValue("platform", store.platform)
                        .addPropertyValue("store", store)
                        .addPropertyValue("job", job)
                        .beanDefinition
                    val beanName = job.id
                    synchronized(this) {
                        if (!applicationContext.containsBean(beanName))
                            applicationContext.registerBeanDefinition(beanName, beanDefinition)
                    }

                    val cron = if (jobInDB.cron.isNullOrBlank()) defaultCron else jobInDB.cron
                    val bean = applicationContext.getBean(beanName, Synchronizer::class.java)
                    if (jobInDB.enabled)
                        taskRegistrar.addCronTask(bean, cron)
                }

                log.info("任务[$jobId]已经启动")
            }
        }
    }

    private fun initScheduler(taskRegistrar: ScheduledTaskRegistrar) {
        val scheduler = ThreadPoolTaskScheduler()
        scheduler.poolSize = Runtime.getRuntime().availableProcessors()
        scheduler.initialize()
        taskRegistrar.setScheduler(scheduler)
    }
}